package com.tanhua.gateway.filters;

import com.alibaba.fastjson.JSON;
import com.tanhua.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 统一鉴权的过滤器
 *   1、实现两个接口
 *   2、实现内部的两个方法
 *   3、在filter方法中，完成统一鉴权的业务逻辑
 *      统一鉴权（验证请求头中的token是否合法）：
 *   4、当前类要交给容器管理
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    //@value会将定义的字符串，根据内部的“，”自动拆分为list
    @Value("${gateway.excludedUrls}")
    private List<String> excludeUrls;//定义不需要，token验证的请求连接

    /**
     * 过滤器的核心业务方法
     * @param exchange  请求上下文对象
     * @param chain  过滤器链 （放行：向后执行）
     * @return
     */
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1、获取请求Request对象
        ServerHttpRequest request = exchange.getRequest();
        //2、获取当前的请求连接
        String path = request.getURI().getPath();  // /login ...
        //3、判断此连接是否需要验证token，如果不需要验证，进行路由转发
        if(excludeUrls.contains(path)) { //path是否在list集合中
            return chain.filter(exchange);
        }
        //4、从请求头中获取token参数
        String token = request.getHeaders().getFirst("Authorization");
        //手机端存入header中的token = token
        //vue页面存入header中的token = Bearer token
        //处理Vue前端传递token的多余字符
        if(!StringUtils.isEmpty(token)) {
            token = token.replaceAll("Bearer ","");//将参数一种的字符，替换为参数二
        }
        //5、调用工具类，验证token
        boolean verifyToken = JwtUtils.verifyToken(token);
        //6、如果token符合要求，进行路由转发
        if(verifyToken) {
            return chain.filter(exchange);
        }else {
            //7、如果token不符合要求，设置响应状态码401，并返回
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
//            return response.setComplete();
            //8、响应数据（工作问题）
            Map<String,Object> map = new HashMap<>();
            map.put("errCode", 401);
            map.put("errMessage", "用户未登录");
            //指定相应的数据头
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            //需要将返回的对象数据转化为byte数组
            byte[] data = JSON.toJSONBytes(map);
            //构造DataBuffer对象
            DataBuffer buffer = response.bufferFactory().wrap(data); //数据DatBuffer
            return response.writeWith(Mono.just(buffer));
        }
    }

    //过滤器的执行顺序（优先级）
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE; //最低（在所有的过滤器中，最后执行）
    }
}
